package com.voodoo.lib_http.utils;

import com.voodoo.lib_http.builder.GetBuilder;
import com.voodoo.lib_http.builder.PostFormBuilder;
import com.voodoo.lib_http.builder.PostStringBuilder;
import com.voodoo.lib_http.callback.Callback;
import com.voodoo.lib_http.request.RequestCall;

import java.io.IOException;
import java.util.concurrent.Executor;

import okhttp3.Call;
import okhttp3.Dispatcher;
import okhttp3.OkHttpClient;
import okhttp3.Response;

/**
 * Author: voodoo
 * CreateDate: 2021/05/29
 * Description: https://github.com/hongyangAndroid/okhttputils
 */
public class OkHttpUtils {

    public static final long DEFAULT_MILLISECONDS = 60_000L;
    private volatile static OkHttpUtils okHttpUtils;
    private static OkHttpClient mOkHttpClient;
    private Platform mPlatform;

    public static OkHttpUtils getInstance() {
        return initClient(null);
    }

    public static OkHttpUtils initClient(OkHttpClient okHttpClient) {
        if (okHttpUtils == null) {
            synchronized (OkHttpUtils.class) {
                if (okHttpUtils == null) {
                    okHttpUtils = new OkHttpUtils(okHttpClient);
                }
            }
        }
        return okHttpUtils;
    }

    public OkHttpUtils(OkHttpClient okHttpClient) {
        if (mOkHttpClient == null) {
            mOkHttpClient = new OkHttpClient();
        } else {
            mOkHttpClient = okHttpClient;
        }
        mPlatform = Platform.get();
    }

    public Executor getDelivery() {
        return mPlatform.defaultCallbackExecutor();
    }

    public static OkHttpClient getOkHttpClient() {
        return mOkHttpClient;
    }

    // ========================================= 请求方式 ==========================================

    /**
     * GET 请求
     *
     * @return GetBuilder
     */
    public static GetBuilder get() {
        return new GetBuilder();
    }

    /**
     * POST 请求
     *
     * @return PostBuilder
     */
    public static PostFormBuilder post() {
        return new PostFormBuilder();
    }

    /**
     * POST String 请求
     *
     * @return
     */
    public static PostStringBuilder postString() {
        return new PostStringBuilder();
    }

    // ========================================= 执行回调 ==========================================

    public void execute(final RequestCall requestCall, Callback callback) {
        if (callback == null) {
            callback = Callback.CALLBACK_DEFAULT;
        }
        final Callback finalCallback = callback;
        final int id = requestCall.getOkHttpRequest().getId();

        requestCall.getCall().enqueue(new okhttp3.Callback() {
            @Override
            public void onFailure(Call call, final IOException e) {
                sendFailResultCallback(call, e, finalCallback, id);
            }

            @Override
            public void onResponse(final Call call, final Response response) {
                try {
                    if (call.isCanceled()) {
                        sendFailResultCallback(call, new IOException("请求被取消"), finalCallback, id);
                        return;
                    }

                    if (!finalCallback.validateReponse(response, id)) {
                        sendFailResultCallback(call, new IOException("请求失败, 异常Code为: " + response.code()), finalCallback, id);
                        return;
                    }

                    Object object = finalCallback.parseNetworkResponse(response, id);
                    sendSuccessResultCallback(object, finalCallback, id);
                } catch (Exception e) {
                    sendFailResultCallback(call, e, finalCallback, id);
                } finally {
                    if (response.body() != null)
                        response.body().close();
                }

            }
        });
    }

    public void sendFailResultCallback(final Call call, final Exception e, final Callback callback, final int id) {
        if (callback == null) {
            return;
        }

        mPlatform.execute(new Runnable() {
            @Override
            public void run() {
                callback.onRequestComplete(id);
                callback.onError(call, e, id);
            }
        });
    }

    public void sendSuccessResultCallback(final Object object, final Callback callback, final int id) {
        if (callback == null) {
            return;
        }
        mPlatform.execute(new Runnable() {
            @Override
            public void run() {
                callback.onRequestComplete(id);
                callback.onResponse(object, id);
            }
        });
    }

    // ========================================= 其他方法 ==========================================

    /**
     * 根据TAG取消请求
     *
     * @param tag 取消的TAG
     */
    public void cancelTag(Object tag) {
        Dispatcher dispatcher = mOkHttpClient.dispatcher();
        // 先解决掉请求队列中的指定TAG的Call
        for (Call call : dispatcher.queuedCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
        // 再清除掉正在请求队列中的指定TAG的Call
        for (Call call : dispatcher.runningCalls()) {
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
    }

}
